package com.chenjj.java.lsp;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {


    static class Something{}
    static class Animal extends  Something {   public String name(){ return  "Animal";}   }
    static class Human extends Animal {  public String name(){ return  "Human";}   }
    static class Wolf extends Animal {  public String name(){ return  "Wolf";}   }
    static class Man extends Human {  public String name(){ return  "Man";}   }
    static class Woman extends Human {  public String name(){ return  "Woman";}   }

    public static void main(String[] args) {

        /**协变：当A≤ B有 f<A> ≤f <B>*/
        //协变，指定了上界为Humen，<? extends T>为子类通配符
        List<? extends Human> list=new ArrayList<Human>();
        List<? extends Human> listA = new ArrayList<Woman>();
        List<? extends Human> listB =new ArrayList<Man>();
        //List<? extends Human> listC =new ArrayList<Animal>(); //编译不通过

        //因为类型擦除，list、listA、listB的Class都是同一个
        System.out.println(list.getClass() == listA.getClass()); //打印true
        System.out.println(listA.getClass()==listB.getClass()); //打印true

        try{
            //因为类型擦除，所以编译器不知道list里存放的东西是什么，但是知道它肯定是Human的子类，所以能够通过可以可以get出Humen以及它的父类的类型
            Object ojb = list.get(0);
            Something something = list.get(0);
            Animal animal = list.get(0);
            Human human = list.get(0);
            //Woman woman = list.get(0); //编译不通过
        }catch (Exception e){

        }

        //因为指定了上界，所以list里不能放入任何东西，编译器不知道list里应该放具体的哪一个，因此编译不通过
        //list.add(new Human());
        //list.add(new Man());


        /**逆变：当A≤ B有 f<B> ≤f <A>*/
        //逆变，指定了下界，<? super T>为超类通配符
        List<? super Human> list1 =new ArrayList<Human>();
        List<? super Human> list1A =new ArrayList<Animal>();
        List<? super Human> list1B =new ArrayList<Something>();
        //List<? super Human> list1C =new ArrayList<Woman>();//编译不通过

        //因为类型擦除，list1、list1A、list1B的Class都是同一个
        System.out.println(list1.getClass() == list1A.getClass()); //打印true
        System.out.println(list1A.getClass()==list1B.getClass()); //打印true

        //因为类型擦除，所以编译器不知道list里存放的东西是什么，但是它知道肯定是Human的父类，所以往list添加Humen的子类是安全的（Humen的子类继承了所有Humen的父类的特性）
        list1.add(new Human());
        list1.add(new Man());
        list1.add(new Woman());
        //list1.add(new Animal());// 编译不通过

        Object ojb1 = list1.get(0);
        //编译不通过，因为没明确指定统一的“根”(除Object)，只能get出Object类型
        //Animal animal1 = list1.get(0);
        //Human human = list1.get(0);
        //Man man = list1.get(0);


        /**不变：当A≤B时上述协变、逆变均不成立*/
        //编译不通过
        //List<Object> list2=new ArrayList<String>();

    }


}
